package rabbit.flt.plugins.reactor.http.plugin.proxy;

import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.Proxy;
import rabbit.flt.common.trace.TraceData;
import reactor.netty.Connection;
import reactor.netty.NettyInbound;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.locks.ReentrantLock;

public class ConnectionProxy implements InvocationHandler {

    private Connection realConnection;

    private NettyInbound inboundResult;

    private TraceData traceData;

    private ReentrantLock lock = new ReentrantLock();

    public static Connection proxy(Connection realObj, TraceData traceData) {
        ConnectionProxy h = new ConnectionProxy();
        h.realConnection = realObj;
        h.traceData = traceData;
        return (Connection) Proxy.newProxyInstance(ConnectionProxy.class.getClassLoader(),
                new Class[]{Connection.class}, h);
    }

    @Override
    public Object invoke(Object o, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        if ("inbound".equals(method.getName())) {
            if (null == inboundResult) {
                initInBound(method, args);
            }
            return inboundResult;
        }
        return method.invoke(realConnection, args);
    }

    private void initInBound(Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        try {
            lock.lock();
            if (null == inboundResult) {
                inboundResult = NettyInboundProxy.proxy((NettyInbound) method.invoke(realConnection, args), traceData);
            }
        } finally {
            lock.unlock();
        }
    }
}
